package test;

import ap.BDDACLWrapper;
import common.Device;
import common.correspondence.BDDIOTransfer;

import java.io.IOException;
import java.util.*;


public class DeviceBatch extends DBconfig{

    int testTimes = 10000;
    public DeviceBatch() {
        deviceConfigs = new HashMap<>();
        devices = new HashMap<>();
        bdd = new BDDACLWrapper().getBDD();
        bt = new BDDIOTransfer(bdd);
    }

    public static void main(String[] args) throws IOException {

        boolean changeInOrder = false;   //是否每次变化控制在times个FIB并且变化可以复原，有序的
        boolean onlyChangePort=false;  //是否只做change port操作

        String[] cT = {"changePort", "del", "insert"};     //顺序执行使用
        forwardChange fw = new forwardChange();

        //改变文件，设定初始的文件改变范围
        //初始第一次划分文件
        String[] s = {"atla", "chic", "hous", "kans", "losa", "salt","newy32aoa"};
        forwardChange fwf = new forwardChange();



        if(onlyChangePort){   //全部fib
            for(String a : s){
                fwf.fwdChangeI2(a + "ap", 1);
                fw.apLength.put(a, fwf.length);  //文件，原始文件长度
            }
        }else {
            for (String a : s) {
                if (changeInOrder) {
                    fwf.fwdChangeI2(a + "ap", 0.8);   //固定变化的顺序
                    fw.apLength.put(a, fwf.length);
                } else {
                    fwf.fwdChangeI2(a + "ap", 0.8, false);  //第一次所有文件划分,m取值0-1，整体的m部分划分到change，余下的作为插入时插入
                    fw.apLength.put(a, fwf.length);
                }
            }
        }
        for (String a : s) {           //指定变化的文件范围默认是全集，想要检测更多difference，使用s1
            fw.nextChangePort.add(a);
            if(!onlyChangePort) {
                fw.nextInsert.add(a);
                fw.nextDel.add(a);
            }
        }

        //开始第一次启动设备
        DeviceBatch db = new DeviceBatch();

        db.setConfigI2();

        db.createDevices();

        db.countStart();

        db.wait(3000);

        while (db.getDPVResult() == null) {
            db.wait(1000);
        }
        int p1 = db.getDPVResult();
        int p2 = db.getAPResult();

        System.out.println("s1 p We=" + p1);
        System.out.println("s2 p Ap=" + p2);
        System.out.println("首次结果=" + (p1 == p2));


        int orderType = 0;
        int orderFile = 0;
        int testTimes=1000;
        //非首次启动结果对比需要的变量
        int logR = 0;
        float equal = 0;
        float notequal = 0;
        float same = 0;
        int p11=p1, p22=p2;
        int ptep1 = 0, ptep2 = 0;
        int numOfcT = 3;
        HashMap<String, Long> memoryUsageLast = null;
        long totallast = 0;
        String fileName = " ";
        String changeType;
        int difference = 0;
        ArrayList<String> errorFile = new ArrayList<>();
        ArrayList<String> errorType = new ArrayList<>();
        ArrayList<Integer> num = new ArrayList<>();
        ArrayList<Integer> diff = new ArrayList<>();
        ArrayList<Integer> differenceTime = new ArrayList<>();
        ArrayList<String> re=new ArrayList<>();
        System.out.println("===================================================");


        if(onlyChangePort){
            numOfcT = 1;
        }

        while (true) {

            fw.portTime++;
            if (changeInOrder) {  //有序变化
                switch (orderType % numOfcT) {
                    case 0:
                        orderFile = orderFile % fw.nextChangePort.size();  //port
                        fileName = fw.nextChangePort.get(orderFile);
                        break;
                    case 1:
                        orderFile = orderFile % fw.nextDel.size();
                        fileName = fw.nextDel.get(orderFile);
                        break;
                    case 2:
                        if (fw.nextInsert.size() > 0) {
                            orderFile = orderFile % fw.nextInsert.size();
                            fileName = fw.nextInsert.get(orderFile);
                        } else {
                            orderFile = orderFile % fw.nextChangePort.size();
                            fileName = fw.nextChangePort.get(orderFile);
                            numOfcT--;
                        }
                        break;

                    default:
                        System.out.println("type error");
                }
                re = fw.forwardChangeTestChangeInOrder(fileName, cT[orderType % numOfcT], 1);  //一次有序变化 inOrderTimes 条
                orderFile++;
                orderType++;
            } else {
                re = fw.forwardChangeTestOneNoSeed();  //随机变化,插完再开始删除
            }

            fileName = re.get(0);
            changeType = re.get(1);

            Device d = db.devices.get(fileName); // 选择device
            if(fw.flChange.size()==0){
                continue;
            }

            //端口处理
            for(int i=0;i<fw.flChange.size();i++){
                if(fw.flChange.get(i).port.contains(".")) {
                    String[] P = fw.flChange.get(i).port.split("\\.");   //去掉port . 后面的
                    fw.flChange.get(i).port = P[0];
                }
            }
            //根据change类型执行函数
            switch (changeType) {
                case "insert":
                    if (fw.flChange.size() > 1) {
                        System.out.println("一次性插入了多条，当前无法处理");
                        break;
                    }

                    d.insertRule(Long.parseLong(fw.flChange.get(0).predicate), Integer.parseInt(fw.flChange.get(0).preLength), fw.flChange.get(0).port); // 第一个参数为long类型 从string中读取时使用Long.parseLong() 第二个为int 第三个为字符串
                    break;
                case "changePort":
                    if (fw.flChange.size() > 2) {
                        System.out.println("一次性改变了多条，当前无法处理");
                        break;
                    }

                    d.modifyRule(Long.parseLong(fw.flChange.get(0).predicate), Integer.parseInt(fw.flChange.get(0).preLength), fw.flChange.get(0).port, fw.flChange.get(1).port); // 前两个同上， 第三个为旧的port 第三个参数为新的port
                    break;
                case "del":
                    if (fw.flChange.size() > 1) {
                        System.out.println("一次性删除了多条，当前无法处理");
                        break;
                    }

                    d.deleteRule(Long.parseLong(fw.flChange.get(0).predicate), Integer.parseInt(fw.flChange.get(0).preLength), fw.flChange.get(0).port); // 同insert
                    break;
                default:
                    System.out.println("error type");
            }


            db.wait(2000);

            p1 = db.getDPVResult();
            p2 = db.getAPResult();
            logR++;
            System.out.println("fileName=" + fileName + "  changeType=" + changeType);


            if (p11 == p1 && p22 == p2) {
                same++;
                System.out.println("same");
            } else {
                System.out.println("difference");
                difference++;
                differenceTime.add((int) (equal + notequal + 1));
            }

            p11 = p1;
            p22 = p2;


            System.out.println("p1We=" + p1);
            System.out.println("p2Ap=" + p2);


            System.out.println("结果" + (int) (equal + notequal + 1) + "=" + (p1 == p2));
            System.out.println();


            //------------------------------------------------------- 打印内存 star-------------------------------------------------
            HashMap<String, Long> memoryUsage = db.getUsage();
            long total = db.getSum(memoryUsage.values());
            if (memoryUsageLast == null) {
                System.out.println(memoryUsage);
                System.out.println("total bdd memory:" + total);
            } else {
                for (String d1 : memoryUsageLast.keySet()) {
                    HashMap<String, Long> finalMemoryUsage = memoryUsage;
                    memoryUsageLast.computeIfPresent(d1, (k, v) -> (finalMemoryUsage.get(d1) - v));
                }
                totallast = total - totallast;
                System.out.println("increase:" + memoryUsageLast);
                System.out.println("total bdd node count increase:" + totallast);
            }

            memoryUsageLast = memoryUsage;
            totallast = total;
            //------------------------------------------------------- 打印内存 end-------------------------------------------------
            if (logR % 20 == 0) {
                db.doCommand("write");
            }

            if (p1 == p2) {
                equal++;
            }
            else {
                db.doCommand("write");
                logR = 0;
                notequal++;
                num.add((int) (equal + notequal));
                errorFile.add(fileName);
                errorType.add(changeType);
                diff.add(difference);
                difference = 0;
                System.out.println("尝试重启设备后重新计算.");
                db.closeAll();
                db.wait(1000);

                db.createDevices();
                db.untilAlready();
                db.countStart();
                db.wait(2000);


                int pt = db.getDPVResult();


                System.out.printf("新结果pt=%s.\n p1 == pt: %s, \n p2 == pt: %s\n", pt, p1 == pt, p2 == pt);

                if (p1 == pt) ptep1++;
                if (p2 == pt) ptep2++;

                memoryUsage = db.getUsage();
                total = db.getSum(memoryUsage.values());
                for (String d1 : memoryUsageLast.keySet()) {
                    HashMap<String, Long> finalMemoryUsage1 = memoryUsage;
                    memoryUsageLast.computeIfPresent(d1, (k, v) -> (finalMemoryUsage1.get(d1) - v));
                }
                totallast = total - totallast;
                System.out.println("after restart, increase:" + memoryUsageLast);
                System.out.println("after restart, total bdd node count  increase:" + totallast);


                memoryUsageLast = memoryUsage;
                totallast = total;

            }


            System.out.println("===================================================");
            if ((equal + notequal) == testTimes ||fw.nextDel.size() < fw.nextChangePort.size()&&!onlyChangePort||fw.nextInsert.size()==0) {  //已经达到运行次数或者已经有一个文件全部删除了，空了，则结束
                System.out.println("正确率=" + equal / (equal + notequal) * 100 + "%");
                System.out.println("相同率=" + (same / (equal + notequal) * 100 + "%"));

                if (notequal > 0) {
                    System.out.printf("错误时，重启设备后重新计算结果与dpv相似率：%.4f%%, 与ap相似率：%.4f%%\n",
                            100 * (1.0 * ptep1 / notequal), 100 * (1.0 * ptep2 / notequal));

                    System.out.println("--------------------出错文件-----------------------");
                    System.out.println("文件名        变化类型        出错序号        两次出错间隔次数         出错两次间difference更新次数");
                }

                for (int i = 0; i < errorFile.size(); i++) {
                    String f = errorFile.get(i);
                    if (f.equals("newy32aoa")) {
                        f = "newy";
                    }
                    if (i > 0) {
                        System.out.println(f + "        " + errorType.get(i) + "        " + num.get(i) + "        " + (num.get(i) - num.get(i - 1) + "        " + diff.get(i)));
                    } else {
                        System.out.println(f + "        " + errorType.get(i) + "        " + num.get(i) + "        " + diff.get(i));
                    }
                }

                if (changeInOrder) {
                    System.out.println("==================================有序多条更改FIB时，结果变化的序号==================================");
                } else {
                    System.out.println("==================================随机单条更改FIB时，结果变化的序号==================================");
                }
                for (Integer i : differenceTime) {
                    System.out.println(i);
                }

               break;
            }
        }
        db.closeAll();
    }


}
